﻿using Castle.Core.Logging;
using PlutoStudio.Aspects;
using PlutoStudio.Configuration.Startup;
using PlutoStudio.Dependency;
using PlutoStudio.Modules;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PlutoStudio
{
    public class Bootstrapper : IDisposable
    {
        /// <summary>
        /// 获取当前 <see cref="IIocManager"/> 对象实例。
        /// </summary>
        public IIocManager IocManager { get; }
        public Type StartupModule { get; }


        #region IDisposable Support
        private bool disposedValue = false; // 要检测冗余调用
        private IModuleManager _moduleManager;
        private ILogger _logger;

        public static Bootstrapper Create(Type startupModule)
        {
            return new Bootstrapper(startupModule);
        }

        public static Bootstrapper Create<TStartupModule>() where TStartupModule : Module
        {
            return new Bootstrapper(typeof(TStartupModule));
        }

        public static Bootstrapper Create(Type startupModule,IIocManager iocManager)
        {
            return new Bootstrapper(startupModule,iocManager);
        }

        public static Bootstrapper Create<TStartupModule>(IIocManager iocManager) where TStartupModule : Module
        {
            return new Bootstrapper(typeof(TStartupModule),iocManager);
        }

        private Bootstrapper(Type startModule):this(startModule,Dependency.IocManager.Instance){
            
        }

        private Bootstrapper(Type startupModule,IIocManager iocManager)
        {
            PublicHelper.CheckArgument(startupModule,nameof(startupModule));
            PublicHelper.CheckArgument(iocManager,nameof(iocManager));
            if (!typeof(Module).IsAssignableFrom(startupModule))
            {
                throw new ArgumentException($"{nameof(startupModule)} should be derived from {typeof(Module)}");
            }
            StartupModule = startupModule;
            IocManager = iocManager;
            _logger = NullLogger.Instance;
        }

        /// <summary>
        /// Initializes the ABP system.
        /// </summary>
        public virtual void Initialize()
        {
            ResolveLogger();
            try
            {
                RegisterBootstrapper();
                IocManager.Install(new CoreInstaller());

                IocManager.Resolve<StartupConfiguration>().Initialize();

                _moduleManager = IocManager.Resolve<IModuleManager>();
                _moduleManager.Initialize(StartupModule);
                _moduleManager.StartModules();
                IocManager.Install(new InterceptorInstaller());

            }
            catch (Exception ex)
            {
                _logger.Fatal(ex.ToString(), ex);
                throw;
            }
        }

        private void ResolveLogger()
        {
            if (IocManager.IsRegistered<ILoggerFactory>())
            {
                _logger = IocManager.Resolve<ILoggerFactory>().Create(typeof(Bootstrapper));
            }
        }

        private void RegisterBootstrapper()
        {
            if (!IocManager.IsRegistered<Bootstrapper>())
            {
                IocManager.Register(this);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    IocManager.Dispose();
                    // TODO: 释放托管状态(托管对象)。
                }
                // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                // TODO: 将大型字段设置为 null。

                disposedValue = true;
            }
        }

        // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
        // ~Bootstrapper() {
        //   // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
        //   Dispose(false);
        // }

        // 添加此代码以正确实现可处置模式。
        public void Dispose()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(true);
            // TODO: 如果在以上内容中替代了终结器，则取消注释以下行。
            // GC.SuppressFinalize(this);
        }
        #endregion
    }
}
